微前端在小米 CRM 系统的实践
(给前端大全加星标,提升前端技能)
作者:木子朗
https://www.lishuaishuai.com/architecture/1344.html
Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. — Micro Frontends
实施微前端的六种方式
路由分发
前端微服务化
微应用
微件化
iframe
HTML 内联框架元素 <iframe>
表示嵌套的正在浏览的上下文,能有效地将另一个 HTML 页面嵌入到当前页面中。
网站不需要 SEO 支持
拥有相应的应用管理机制。
Web Components
真实的业务场景
统一的域名
统一的界面和交互
系统需要方便拓展
不希望开发阶段每个系统有独立的代码仓库
CI 构建
怎么改造?
关键点
申请统一的域名(暂且称之为crm.mi.com)
将 old-a 和 old-b 两个老旧的系统样式调整,像系统C靠拢
三个系统使用统一的菜单和权限
三个系统使用统一的 SSO
C 系统和正在开发的 X 个系统使用 CI 解决打包和手动 copy 的问题
微前端几种方式对比
实施
一些问题
子应用注册方式
// single-spa-config.js
import{ registerApplication, start } from'single-spa'
registerApplication("applicationName", loadingFunction, activityFunction)
start()
function loadingFunction() {
returnimport("src/app1/main.js")
}
function activityFunction(location) {
return location.pathname.indexOf("/app1/") === 0
}
// single-spa-config.js
import* as singleSpa from'single-spa'
import config from'./manifest.json'
registerApp(config)
singleSpa.start()
function registerApp(conf) {
conf.forEach(application => {
singleSpa.registerApplication(
application.name,
() => import(`./${application.name}.app/index.js`),
pathPrefix(application.activeRule, application.strict),
)
})
}
function pathPrefix(prefix, strict) {
returnfunction(location) {
if(strict) {
return location.pathname === prefix
}
return location.pathname.startsWith(`${prefix}`)
}
}
// manifest.json
[
{
"name": "layout",
"activeRule": "/"
},
{
"name": "welcome",
"activeRule": "/",
"strict": true
},
{
"name": "iframe",
"activeRule": "/link"
},
{
"name": "app1",
"activeRule": "/app1"
},
{
"name": "app2",
"activeRule": "/app2"
}
]
共享cookie
应用之间数据共享及通信
// 应用 A
window.dispatchEvent(
newCustomEvent('iframe:change', { detail: { path: '/a/b/c'} })
)
// 应用 B
window.addEventListener('iframe:change', (event) => {
console.log(event.detail.path)
})
css隔离
postcss.plugin('postcss-plugin-namespace', function() {
returnfunction(css) {
css.walkRules(rule => {
if(rule.parent && rule.parent.type === 'atrule'&& rule.parent.name !== 'media') return
const filePath = rule.source && rule.source.input.file
const appName = /src\/(\S*?)\//.exec(filePath)[1] || ''
constnamespace= appName.split('.')[0] || ''
rule.selectors = rule.selectors.map(s => `#${namespace} ${s === 'body' ? '' : s}`)
})
}
})
js沙箱
优化体验 PWA
创建桌面图标,快速访问
Service Worker 缓存,对大文件和不经常更改的文件缓存,优化加载。
还可以做什么?
可以使用 lerna 统一管理所有项目,方便维护,或者让每个应用拥有独立的仓库,做到独立开发。
可以使用 SystemJS 实现应用的动态加载、独立部署。
总结
觉得本文对你有帮助?请分享给更多人
关注「前端大全」加星标,提升前端技能
好文章,我在看❤️